#include "enesim_parser.h"

Eina_List *renderers = NULL;

static char * strlower(char *str)
{
	char *tmp;
	int i;

	tmp = strdup(str);
	for (i = 0; tmp[i]; i++)
		tmp[i] = tolower(tmp[i]);

	return tmp;
}

static char * strcamel(char *str)
{

}

static void generate_callback_coord(Renderer *r, Property *p)
{
	printf("static void on_%s_x_changed(GtkSpinButton *spin, gpointer user_data)\n", p->name);
	printf("{\n");
	printf("\t%s *r = user_data;\n", r->name);
	printf("\tgfloat y;\n");
	printf("\tguint value;\n");
	printf("\tvalue = gtk_spin_button_get_value_as_int(spin);\n");
	printf("\t%s_%s_get(r->renderer, NULL, &y);\n", r->name, p->name);
	printf("\t%s_%s_set(r->renderer, value, y);\n", r->name, p->name);
	printf("\tapplication_render(r->app);\n");
	printf("}\n");
	printf("static void on_%s_y_changed(GtkSpinButton *spin, gpointer user_data)\n", p->name);
	printf("{\n");
	printf("\t%s *r = user_data;\n", r->name);
	printf("\tgfloat x;\n");
	printf("\tguint value;\n");
	printf("\tvalue = gtk_spin_button_get_value_as_int(spin);\n");
	printf("\t%s_%s_get(r->renderer, &x, NULL);\n", r->name, p->name);
	printf("\t%s_%s_set(r->renderer, x, value);\n", r->name, p->name);
	printf("\tapplication_render(r->app);\n");
	printf("}\n");
}

static void generate_callback_surface(Renderer *r, Property *p)
{
	printf("static void on_%s_changed(GtkFileChooserButton *widget, gpointer user_data)\n", p->name);
	printf("{\n");
	printf("\t%s *r = user_data;\n", r->name);
	printf("\tEnesim_Surface *surface = NULL;\n");
	printf("\tgchar *file;\n");
	printf("\tfile = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(widget));\n");
	printf("\tprintf(\"file = %%s\\n\", file);\n");
	printf("\tenesim_image_file_load(file, &surface, ENESIM_FORMAT_ARGB8888, NULL, NULL);\n");
	printf("\t%s_%s_set(r->renderer, surface);\n", r->name, p->name);
	printf("\tg_free(file);\n");
	printf("\tapplication_render(r->app);\n");
	printf("}\n");
}

static void generate_callback_color(Renderer *r, Property *p)
{
	printf("static void on_%s_changed(GtkColorButton *widget, gpointer user_data)\n", p->name);
	printf("{\n");
	printf("\t%s *r = user_data;\n", r->name);
	printf("\tEnesim_Color color;\n");
	printf("\tGdkColor gdkcolor;\n");
	printf("\tguint16 alpha;\n");
	printf("\tgtk_color_button_get_color(widget, &gdkcolor);\n");
	printf("\talpha = gtk_color_button_get_alpha(widget);\n");
	printf("\tenesim_color_from_gdk(&color, &gdkcolor, alpha);\n");
	printf("\t%s_%s_set(r->renderer, color);\n", r->name, p->name);
	printf("\tapplication_render(r->app);\n");
	printf("}\n");
}

static void generate_callback_unsigned_int(Renderer *r, Property *p)
{
	char *lower;

	printf("static void on_%s_changed(GtkSpinButton *spin, gpointer user_data)\n", p->name);
	printf("{\n");
	printf("\t%s *r = user_data;\n", r->name);
	printf("\tguint value;\n");
	printf("\tvalue = gtk_spin_button_get_value_as_int(spin);\n");
	printf("\t%s_%s_set(r->renderer, value);\n", r->name, p->name);
	printf("\tapplication_render(r->app);\n");
	printf("}\n");
}

static void generate_callback_float_double(Renderer *r, Property *p)
{
	printf("static void on_%s_changed(GtkSpinButton *spin, gpointer user_data)\n", p->name);
	printf("{\n");
	printf("\t%s *r = user_data;\n", r->name);
	printf("\tgdouble value;\n");
	printf("\tvalue = gtk_spin_button_get_value(spin);\n");
	printf("\t%s_%s_set(r->renderer, value);\n", r->name, p->name);
	printf("\tapplication_render(r->app);\n");
	printf("}\n");
}

static void generate_callback_string(Renderer *r, Property *p)
{
	printf("static void on_%s_deleted_changed(GtkEntryBuffer *buffer, guint position, guint n_chars, gpointer user_data)\n", p->name);
	printf("{\n");
	printf("\t%s *r = user_data;\n", r->name);
	printf("\tconst gchar *value;\n");
	printf("\tvalue = gtk_entry_buffer_get_text(buffer);\n");
	printf("\t%s_%s_set(r->renderer, value);\n", r->name, p->name);
	printf("\tapplication_render(r->app);\n");
	printf("}\n");
	
	printf("static void on_%s_inserted_changed(GtkEntryBuffer *buffer, guint position, gchar *chars, guint n_chars, gpointer user_data)\n", p->name);
	printf("{\n");
	printf("\t%s *r = user_data;\n", r->name);
	printf("\tconst gchar *value;\n");
	printf("\tvalue = gtk_entry_buffer_get_text(buffer);\n");
	printf("\t%s_%s_set(r->renderer, value);\n", r->name, p->name);
	printf("\tapplication_render(r->app);\n");
	printf("}\n");
}

static void generate_widget_surface(Renderer *r, Property *p)
{
	printf("\t{\n");
	printf("\t\tGtkWidget *label, *file;\n");
	printf("\t\tlabel = gtk_label_new(\"%s\");\n", p->name);
	printf("\t\tgtk_container_add(GTK_CONTAINER(box), label);\n");
	printf("\t\tgtk_widget_show(label);\n");
	printf("\t\tfile = gtk_file_chooser_button_new(\"Select an Image\", GTK_FILE_CHOOSER_ACTION_OPEN);\n");
	printf("\t\tg_signal_connect(file, \"file-set\", G_CALLBACK(on_%s_changed), container);\n", p->name);
	printf("\t\tgtk_container_add(GTK_CONTAINER(box), file);\n");
	printf("\t\tgtk_widget_show(file);\n");
	printf("\t}\n");
}

static void generate_widget_color(Renderer *r, Property *p)
{
	printf("\t{\n");
	printf("\t\tGtkWidget *label, *color;\n");
	printf("\t\tlabel = gtk_label_new(\"%s\");\n", p->name);
	printf("\t\tgtk_container_add(GTK_CONTAINER(box), label);\n");
	printf("\t\tgtk_widget_show(label);\n");
	printf("\t\tcolor = gtk_color_button_new();\n");
	printf("\t\tgtk_color_button_set_use_alpha(GTK_COLOR_BUTTON(color), TRUE);\n");
	printf("\t\tg_signal_connect(color, \"color-set\", G_CALLBACK(on_%s_changed), container);\n", p->name);
	printf("\t\tgtk_container_add(GTK_CONTAINER(box), color);\n");
	printf("\t\tgtk_widget_show(color);\n");
	printf("\t}\n");
}

static void generate_widget_unsigned_int(Renderer *r, Property *p)
{
	printf("\t{\n");
	printf("\t\tGtkWidget *label, *spin;\n");
	printf("\t\tlabel = gtk_label_new(\"%s\");\n", p->name);
	printf("\t\tgtk_container_add(GTK_CONTAINER(box), label);\n");
	printf("\t\tgtk_widget_show(label);\n");
	printf("\t\tspin = gtk_spin_button_new_with_range(1, 256, 1);\n");
	printf("\t\tg_signal_connect(spin, \"value-changed\", G_CALLBACK(on_%s_changed), container);\n", p->name);
	printf("\t\tgtk_container_add(GTK_CONTAINER(box), spin);\n");
	printf("\t\tgtk_widget_show(spin);\n");
	printf("\t}\n");
}

static void generate_widget_float_double(Renderer *r, Property *p)
{
	printf("\t{\n");
	printf("\t\tGtkWidget *label, *spin;\n");
	printf("\t\tlabel = gtk_label_new(\"%s\");\n", p->name);
	printf("\t\tgtk_container_add(GTK_CONTAINER(box), label);\n");
	printf("\t\tgtk_widget_show(label);\n");
	printf("\t\tspin = gtk_spin_button_new_with_range(1.0, 256.0, 0.5);\n");
	printf("\t\tg_signal_connect(spin, \"value-changed\", G_CALLBACK(on_%s_changed), container);\n", p->name);
	printf("\t\tgtk_container_add(GTK_CONTAINER(box), spin);\n");
	printf("\t\tgtk_widget_show(spin);\n");
	printf("\t}\n");
}

static void generate_widget_coord(Renderer *r, Property *p)
{
	printf("\t{\n");
	printf("\t\tGtkWidget *label, *spin;\n");
	printf("\t\tlabel = gtk_label_new(\"%s x\");\n", p->name);
	printf("\t\tgtk_container_add(GTK_CONTAINER(box), label);\n");
	printf("\t\tgtk_widget_show(label);\n");
	printf("\t\tspin = gtk_spin_button_new_with_range(1.0, 256.0, 0.5);\n");
	printf("\t\tg_signal_connect(spin, \"value-changed\", G_CALLBACK(on_%s_x_changed), container);\n", p->name);
	printf("\t\tgtk_container_add(GTK_CONTAINER(box), spin);\n");
	printf("\t\tgtk_widget_show(spin);\n");
	printf("\t}\n");
	printf("\t{\n");
	printf("\t\tGtkWidget *label, *spin;\n");
	printf("\t\tlabel = gtk_label_new(\"%s y\");\n", p->name);
	printf("\t\tgtk_container_add(GTK_CONTAINER(box), label);\n");
	printf("\t\tgtk_widget_show(label);\n");
	printf("\t\tspin = gtk_spin_button_new_with_range(1.0, 256.0, 0.5);\n");
	printf("\t\tg_signal_connect(spin, \"value-changed\", G_CALLBACK(on_%s_y_changed), container);\n", p->name);
	printf("\t\tgtk_container_add(GTK_CONTAINER(box), spin);\n");
	printf("\t\tgtk_widget_show(spin);\n");
	printf("\t}\n");
}

static void generate_widget_string(Renderer *r, Property *p)
{
	printf("\t{\n");
	printf("\t\tGtkWidget *label, *entry;\n");
	printf("\t\tGtkEntryBuffer *ebuffer;\n");
	printf("\t\tlabel = gtk_label_new(\"%s\");\n", p->name);
	printf("\t\tgtk_container_add(GTK_CONTAINER(box), label);\n");
	printf("\t\tgtk_widget_show(label);\n");
	printf("\t\tentry = gtk_entry_new();\n");
	printf("\t\tebuffer = gtk_entry_get_buffer(GTK_ENTRY(entry));\n");
	printf("\t\tg_signal_connect(ebuffer, \"inserted-text\", G_CALLBACK(on_%s_inserted_changed), container);\n", p->name);
	printf("\t\tg_signal_connect(ebuffer, \"deleted-text\", G_CALLBACK(on_%s_deleted_changed), container);\n", p->name);
	printf("\t\tgtk_container_add(GTK_CONTAINER(box), entry);\n");
	printf("\t\tgtk_widget_show(entry);\n");
	printf("\t}\n");

}

static void generate_property_callbacks(Renderer *r, Property *p)
{
	switch (p->type)
	{
		case PROPERTY_UNSIGNED_INT:
		generate_callback_unsigned_int(r, p);
		break;

		case PROPERTY_COLOR:
		generate_callback_color(r, p);
		break;

		case PROPERTY_DOUBLE:
		case PROPERTY_FLOAT:
		generate_callback_float_double(r, p);
		break;

		case PROPERTY_SURFACE:
		generate_callback_surface(r, p);
		break;

		case PROPERTY_COORD:
		generate_callback_coord(r, p);
		break;

		case PROPERTY_STRING:
		generate_callback_string(r, p);
		break;

		default:
		break;
	}
}

static void generate_property_widget(Renderer *r, Property *p)
{
	switch (p->type)
	{
		case PROPERTY_UNSIGNED_INT:
		generate_widget_unsigned_int(r, p);
		break;

		case PROPERTY_COLOR:
		generate_widget_color(r, p);
		break;

		case PROPERTY_DOUBLE:
		case PROPERTY_FLOAT:
		generate_widget_float_double(r, p);
		break;

		case PROPERTY_SURFACE:
		generate_widget_surface(r, p);
		break;

		case PROPERTY_COORD:
		generate_widget_coord(r, p);
		break;

		case PROPERTY_STRING:
		generate_widget_string(r, p);
		break;

		default:
		break;
	}
}

static void generate_renderer(Renderer *r)
{
	Eina_List *l;
	char *lower;
	Property *property;

	lower = strlower(r->name);
	printf("#include \"demo.h\"\n");
	/* the typedef */
	printf("typedef struct _%s\n", lower);
	printf("{\n");
	printf("\tEnesim_Renderer *renderer;\n");
	printf("\tApplication *app;\n");
	printf("} %s;\n\n", lower);
	EINA_LIST_FOREACH(r->properties, l, property)
	{
		generate_property_callbacks(r, property);
	}
	/* the properties callbacks */
	/* the main entry point */
	printf("Enesim_Renderer * %s_setup(Application *app, GtkWidget *frame)\n", r->name);
	printf("{\n");
	printf("\tEnesim_Renderer *r;\n");
	printf("\t%s *container;\n", r->name);
	printf("\tGtkWidget *box;\n");

	printf("\tr = %s_new();\n", r->name);
	printf("\tcontainer = malloc(sizeof(%s));\n", r->name);
	printf("\tcontainer->renderer = r;\n");
	printf("\tcontainer->app = app;\n");
	printf("\tbox = gtk_hbox_new(FALSE, 0);\n");
	printf("\tgtk_container_add(GTK_CONTAINER(frame), box);\n");
	if (r->parent)
	{
		printf("\t%s_setup(app, box);\n", r->parent);
	}
	printf("\tgtk_widget_show(box);\n");

	/* setup every property */
	EINA_LIST_FOREACH(r->properties, l, property)
	{
		generate_property_widget(r, property);
	}
	printf("\treturn r;\n");
	printf("}\n");
	free(lower);
}

int main(void)
{
	Renderer *r;

	eina_init();
	yyparse();
	EINA_LIST_FREE(renderers, r)
	{
		generate_renderer(r);
		free(r->name);
		free(r);
	}
	eina_shutdown();
	return 0;
}
